
#pragma once
#include <string>
#include <memory>
#include <functional>
#include "fields.hpp"

namespace myrpc{
    // 基础消息基类
    class BaseMessage{
    public:
        using ptr = std::shared_ptr<BaseMessage>;
        virtual ~BaseMessage() {}
        // 设置消息类型
        virtual void setMsgType(MsgType msg_type){
            _msg_type = msg_type;
        }
        // 获取消息类型
        virtual MsgType getMsgType(){
            return _msg_type;
        }
        // 设置消息唯一标识ID
        virtual void setMsgId(const std::string &msg_id){
            _msg_id = msg_id;
        }
        // 获取消息唯一标识ID
        virtual std::string getMsgId(){
            return _msg_id;
        }
        // 消息序列化和反序列化
        virtual std::string serialize() = 0;
        virtual bool unserialize(const std::string &body) = 0;
        // 反序列化后消息字段检测
        virtual bool check() = 0;

    private:
        std::string _msg_id;
        MsgType _msg_type;
    };

    // 基础消息缓冲区基类
    class BaseBuffer{
    public:
        using ptr = std::shared_ptr<BaseBuffer>;

        virtual ~BaseBuffer(){}
        // 获取可读大小
        virtual size_t readableBytes() = 0;
        // 读取四字节数据但不从缓冲区中删除
        virtual int32_t peekInt32() = 0;
        // 从缓冲区中删除四字节数据
        virtual void retrieveInt32() = 0;
        // 读取四字节数据并删除
        virtual int32_t readInt32() = 0;
        // 以字符串的形式读取指定长度的数据
        virtual std::string retrieveAsString(size_t len) = 0;
    };

    // 基础协议基类
    class BaseProtocol{
    public:
        using ptr = std::shared_ptr<BaseProtocol>;

        virtual ~BaseProtocol(){}
        // 判断当前缓冲区中是否可以取出完整的一条消息
        virtual bool canProcessed(const BaseBuffer::ptr &buf) = 0;
        // 从缓冲区中获取消息进行处理
        virtual bool onMessage(const BaseBuffer::ptr &buf, BaseMessage::ptr &msg) = 0;
        // 将指定消息序列化
        virtual std::string serialize(const BaseMessage::ptr &msg) = 0;
    };

    // 基础连接基类
    class BaseConnection{
    public:
        using ptr = std::shared_ptr<BaseConnection>;

        virtual ~BaseConnection(){}
        // 发送序列化后的消息
        virtual void send(const BaseMessage::ptr &msg) = 0;
        // 关闭连接
        virtual void shutdown() = 0;
        // 判断连接是否关闭
        virtual bool connected() = 0;
    };

    // 重命名可调用函数对象名
    using ConnectionCallBack = std::function<void(const BaseConnection::ptr &)>;
    using CloseCallBack = std::function<void(const BaseConnection::ptr &)>;
    using MessageCallBack = std::function<void(const BaseConnection::ptr &, BaseMessage::ptr &)>;

    // 基础服务端基类
    class BaseServer{
    public:
        using ptr = std::shared_ptr<BaseServer>;

        virtual ~BaseServer(){}
        // 设置用户层连接建立后的回调处理
        virtual void setConnectionCallBack(const ConnectionCallBack &cb_conn){
            _cb_conn = cb_conn;
        }
        // 设置用户层连接关闭后的回调处理
        virtual void setCloseCallBack(const CloseCallBack &cb_close){
            _cb_close = cb_close;
        }
        // 设置用户层收到消息后的回调处理 (系统回调会进行缓冲区中的数据处理 将处理好后的消息对象传递给用户回调)
        virtual void setMessageCallBack(const MessageCallBack &cb_message){
            _cb_message = cb_message;
        }
        virtual void start() = 0;

    protected:
        ConnectionCallBack _cb_conn;
        CloseCallBack _cb_close;
        MessageCallBack _cb_message;
    };

    // 基础客户端基类
    class BaseClient{
    public:
        using ptr = std::shared_ptr<BaseClient>;

        virtual ~BaseClient(){}
        virtual void setConnectionCallBack(const ConnectionCallBack &cb_conn){
            _cb_conn = cb_conn;
        }
        virtual void setCloseCallBack(const CloseCallBack &cb_close){
            _cb_close = cb_close;
        }
        virtual void setMessageCallBack(const MessageCallBack &cb_message){
            _cb_message = cb_message;
        }
        // 建立连接
        virtual void connect() = 0;
        // 关闭连接
        virtual void shutdown() = 0;
        // 判断连接是否存在
        virtual bool connected() = 0;
        // 发送序列化后的消息
        virtual bool send(const BaseMessage::ptr &msg) = 0;
        // 获取连接
        virtual BaseConnection::ptr connection() = 0;

    protected:
        ConnectionCallBack _cb_conn;
        CloseCallBack _cb_close;
        MessageCallBack _cb_message;
    };
}